{% extends "base.html" %}

{% block main %}
<div id="app" class="container-lg m-4">
    <div class="row mt-2">
        <div class="col-md-12 mt-2">
            <div class="card" >
                <div class="card-header" >
                    <span class="badge badge-success" v-if="model == 1">Online Model</span>
                    <span class="badge badge-warning" v-if="model == 2">Snapshot Model</span>
                    <div>
                        <i class="fa fa-server fa-2x"></i> 
                        <label class="h-title">  {% raw %}{{ds.master}}{% endraw %} </br></label><br>
                        Last update: {% raw %}{{ds.ts}}{% endraw %} <br>
                    </div>

                    <table id="baseStatsTable" class="tablesorter table table-striped">
                        <thead>
                            <tr>
                                <th>ServerName</th>
                                <th>Start time</th>
                                <th>Last contact</th>
                                <th>Version</th>
                                <th>Requests Per Second</th>
                                <th>Num. Regions</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(d,index) in ds.ds">
                                <td><a :href="'/server?sId='+index">{% raw %}{{d.ServerName}}{% endraw %}</a></td>
                                <td>{% raw %}{{d.baseStatsTable.Start_time}}{% endraw %}</td>
                                <td>{% raw %}{{d.baseStatsTable.Last_contact}}{% endraw %}</td>
                                <td>{% raw %}{{d.baseStatsTable.Version}}{% endraw %}</td>
                                <td>{% raw %}{{d.baseStatsTable.Requests_Per_Second}}{% endraw %}</td>
                                <td>{% raw %}{{d.baseStatsTable.Num_Regions}}{% endraw %}</td>
                            </tr>
                        </tbody>
                    </table>
                </div>

                <div class="card-body">
                    <div class="row">
                        <div class="col-md-12">
                            <div id="requestChart" style="height:320px; "></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        

        <div class="col-md-12 mt-2">
            <div class="card" >
                <div class="card-header" >
                    <div>
                        <i class="fa fa-files-o fa-2x"></i>
                        <label class="b-title">Request Status</label>
                       </div> 
                       
                    <table id="requestStatsTable" class="tablesorter table table-striped">
                        <thead>
                            <tr>
                                <th>ServerName</th>
                                <th>Request Per Second</th>
                                <th>Read Request Count</th>
                                <th>Filtered Read Request Count</th>
                                <th>Write Request Count</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(d,index) in ds.ds">
                                <td><a :href="'/server?sId='+index">{% raw %}{{d.ServerName}}{% endraw %}</a></td>
                                <td>{% raw %}{{d.requestStatsTable.Request_Per_Second}}{% endraw %}</td>
                                <td>{% raw %}{{d.requestStatsTable.Read_Request_Count | formatNum}}{% endraw %}</td>
                                <td>{% raw %}{{d.requestStatsTable.Filtered_Read_Request_Count}}{% endraw %}</td>
                                <td>{% raw %}{{d.requestStatsTable.Write_Request_Count}}{% endraw %}</td>
                            </tr>
                        </tbody>
                    </table>
                </div>

                <div class="card-body">
                    <div class="row">
                        <div id="requestReadChart" class="col-md-4" style="height:320px;"></div>
                        <div id="requestWriteChart" class="col-md-4" style="height:320px;"></div>
                        <div id="requestFilteredChart" class="col-md-4" style="height:320px;"></div>            
                    </div>
                </div>
            </div>
        </div>

        <div class="col-md-12 mt-2">
            <div class="card" >
                <div class="card-header" >
                    <div>
                        <i class="fa fa-pie-chart fa-2x"></i>
                        <label class="b-title">Memory Status</label>
                    </div>

                    <table id="memoryStatsTable" class="tablesorter table table-striped">
                        <thead>
                            <tr>
                                <th>ServerName</th>
                                <th>Used Heap</th>
                                <th>Max Heap</th>
                                <th>Memstore Size</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(d,index) in ds.ds">
                                <td><a :href="'/server?sId='+index">{% raw %}{{d.ServerName}}{% endraw %}</a></td>
                                <td>{% raw %}{{d.memoryStatsTable.Used_Heap | formatStorageUnit}}{% endraw %}</td>
                                <td>{% raw %}{{d.memoryStatsTable.Max_Heap | formatStorageUnit}}{% endraw %}</td>
                                <td>{% raw %}{{d.memoryStatsTable.Memstore_Size | formatStorageUnit}}{% endraw %}</td>
                            </tr>
                        </tbody>
                    </table>
                </div>

                <div class="card-body">
                    <div class="row">
                        <div id="heapChart" class="col-md-6" style="height:320px; "></div>
                        <div id="heapUsedChart" class="col-md-6" style="height:320px; "></div>
                    </div>
                </div>
            </div>
        </div>


        <div class="col-md-12 mt-2 ">
        <div class="card" >
                <div class="card-header" >
                    <div>
                        <i class="fa fa-folder-open-o fa-2x"></i>
                        <label class="b-title">Store Status</label>
                    </div>
                    <table id="storeStatsTable" class="tablesorter table table-striped">
                        <thead>
                            <tr>
                                <th>ServerName</th>
                                <th>Num. Stores</th>
                                <th>Num. Storefiles</th>
                                <th>Storefile Size Uncompressed</th>
                                <th>Storefile Size</th>
                                <th>Index Size</th>
                                <th>Bloom Size</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(d,index) in ds.ds">
                                <td><a :href="'/server?sId='+index">{% raw %}{{d.ServerName}}{% endraw %}</a></td>
                                <td>{% raw %}{{d.storeStatsTable.Num_Stores | formatNum}}{% endraw %}</td>
                                <td>{% raw %}{{d.storeStatsTable.Num_Storefiles | formatNum}}{% endraw %}</td>
                                <td>{% raw %}{{d.storeStatsTable.Storefile_Size_Uncompressed | formatStorageUnit}}{% endraw %}</td>
                                <td>{% raw %}{{d.storeStatsTable.Storefile_Size | formatStorageUnit}}{% endraw %}</td>
                                <td>{% raw %}{{d.storeStatsTable.Index_Size | formatStorageUnit}}{% endraw %}</td>
                                <td>{% raw %}{{d.storeStatsTable.Bloom_Size | formatStorageUnit}}{% endraw %}</td>
                            </tr>
                        </tbody>
                    </table>
                </div>

                <div class="card-body">
                    <div class="row">
                        <div id="storefileSizeChart" class="col-md-12" style="height:320px; "></div>       
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-12 mt-2 ">
            <div class="card" >
                <div class="card-header" >
                    <div>
                        <i class="fa fa-gears fa-2x"></i>
                        <label class="b-title">Compaction Status</label>
                    </div>
                    <table id="compactionStatsTable" class="tablesorter table table-striped">
                        <thead>
                            <tr>
                                <th>ServerName</th>
                                <th>Num. Compacting Cells</th>
                                <th>Num. Compacted Cells</th>
                                <th>Remaining Cells</th>
                                <th>Compaction Progress</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(d,index) in ds.ds">
                                <td><a :href="'/server?sId='+index">{% raw %}{{d.ServerName}}{% endraw %}</a></td>
                                <td>{% raw %}{{d.compactionStatsTable.Num_Compacting_Cells | formatNum}}{% endraw %}</td>
                                <td>{% raw %}{{d.compactionStatsTable.Num_Compacted_Cells | formatNum}}{% endraw %}</td>
                                <td>{% raw %}{{d.compactionStatsTable.Remaining_Cells | formatNum}}{% endraw %}</td>
                                <td>{% raw %}{{d.compactionStatsTable.Compaction_Progress }}{% endraw %}</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div id="compactingChart" class="col-md-6" style="height:320px; "></div>
                        <div id="compactedChart" class="col-md-6" style="height:320px; "></div>
                    </div>
                </div>
            </div>
        </div>

    </div>
</div>
{% endblock %}

{% block vue %}
<script>

    new Vue({
        el: '#app',
        data() {
            return {
                model:0,  //1：实时模式，2：快照模式
                job:null, //用于快照模式清除轮询任务

                id: 0,
                idRange: [-1,-1],
                //redraw : true,
                shift: false,

                ds: {},
                ss: [],//Servers
                colors: ['#058DC7', '#50B432', '#ED561B', '#fabc05', '#d85758','#862586'],
                request: {
                    chart: null,
                    series: [],
                    max_Request_Per_Second: 0,
                },
                xNum: 1, //当xNum > 100时，shift = true
                maxNum: 50,
             
                heap: { chart: null, series: [{ name: 'Free Heap', data: [] }, { name: 'Used Heap', data: [] }], },
                heapUsed: { chart: null, series: [], },

                requestRead: { chart: null, series: []},
                requestFiltered: { chart: null, series: []},
                requestWrite: { chart: null, series: []},

                storefileSize:{chart:null,series:[]},
                compacting:{chart:null,series:[]},
                compacted:{chart:null,series:[]},
            }
        },
        mounted() {
            this.init();
        },
        methods: {
            init() {
                let st = this.getQueryString('st');
                let et = this.getQueryString('et');

                st = new Date(st).getTime() / 1000;
                et = new Date(et).getTime() / 1000;

                if(st==null || et==null || isNaN(st) || isNaN(et) || st >= et){
                    this.startM1();
                }else{  //尝试进入M2
                    axios.get("/api/getIdRange", {params: { 'st': st,'et': et } }).then(
                    (res) => {
                        let idRange = res.data.data.idRange;
                        if(idRange[0] != -1 && idRange[1] != -1){ //如果idRange合法
                            this.idRange = idRange;
                            this.startM2(); //启动M2
                        }else{
                            this.startM1(); //转到M1
                        }
                    })
                    .catch(function (error) { console.log(error); });
                }
            },
            startM1(){
                this.model = 1;
                console.log("Real Time Model...")
                this.getFirstData();
                this.job = setInterval(this.getNextData, 3000);
            },
            startM2(){
                this.model = 2;
                console.log("Snapshoot Model...")
                this.id = this.idRange[0];
                this.maxNum = 200; //扩大maxNum;
                //this.redraw = false;
                this.getFirstData();
                this.job = setInterval(this.getNextData, 100);
            },
            initCharts() {
                this.ds.ds.forEach(d => {
                    this.request.series.push({ name: d.ServerName, data: [] })
                    this.heapUsed.series.push({ name: d.ServerName, data: [] })
                    this.requestRead.series.push({ name: d.ServerName, data: [] })
                    this.requestFiltered.series.push({ name: d.ServerName, data: [] })
                    this.requestWrite.series.push({ name: d.ServerName, data: [] })
                    this.storefileSize.series.push({ name: d.ServerName, data: [] })
                    this.compacting.series.push({ name: d.ServerName, data: [] })
                    this.compacted.series.push({ name: d.ServerName, data: [] })
                });

                Highcharts.setOptions({ global: { useUTC: false } })//设置时区

                this.request.chart = new Highcharts.Chart('requestChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    // chart: { type: 'areaspline', },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Requests Per Second' },
                    colors: this.colors,
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    series: this.request.series, //series: [  { name: 'total',  data: [['2020-01-01',1],['2020-01-01',2]] }]
                });


                this.requestRead.chart = new Highcharts.Chart('requestReadChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Read Request Count'},
                    colors: this.colors,
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    tooltip: {formatter: function () {
                        return  this.series.name + '<br/>' +'<b> Count: ' + Highcharts.numberFormat(Math.abs(this.point.y), 0)+"</b>";}},
                    series: this.requestRead.series,
                });

                this.requestWrite.chart = new Highcharts.Chart('requestWriteChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Write Request Count' },
                    colors: this.colors,
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    tooltip: {formatter: function () {
                        return  this.series.name + '<br/>' +'<b> Count: ' + Highcharts.numberFormat(Math.abs(this.point.y), 0)+"</b>";}},
                    series: this.requestWrite.series,
                });

                this.requestFiltered.chart = new Highcharts.Chart('requestFilteredChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Filtered Read Request Count' },
                    colors: this.colors,
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    tooltip: {formatter: function () {
                        return  this.series.name + '<br/>' +'<b> Count: ' + Highcharts.numberFormat(Math.abs(this.point.y), 0)+"</b>";}},
                    series: this.requestFiltered.series,
                });

                this.heap.chart = new Highcharts.Chart('heapChart', {
                    credits: { enabled: false },
                    chart: { type: 'column' },
                    title: { text: 'Heap' },
                    boost: { useGPUTranslations: true },
                    xAxis: { categories: [] },
                    yAxis: { min: 0, title: { text: '' } },
                    legend: {align: 'right', x: -30, verticalAlign: 'top', y: 25, floating: true,
                        backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
                        borderColor: '#CCC', borderWidth: 1, shadow: false},
                    colors:['#8fdcfc','#047bae','#bbe8ad','#469e2c','#f8c0aa','#d64811','#fde6a1','#dba504','#f0c0c0','#d13839','#e39be3','#752075'],
                    tooltip: { pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.percentage:.0f}%</b>' },
                    plotOptions: { column: { stacking: 'percent' } },
                    series: this.heap.series,
                });

                this.heapUsed.chart = new Highcharts.Chart('heapUsedChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Used Heap' },
                    colors: this.colors,
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    tooltip: { valueSuffix: ' MB' },
                    series: this.heapUsed.series,
                });

                this.storefileSize.chart = new Highcharts.Chart('storefileSizeChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Storefile Size' },
                    colors: this.colors,
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    tooltip: {formatter: function () {
                        let d = this.point.y;
                        if (d >= 1073741824) return this.series.name  +': <b>' + Highcharts.numberFormat(d / 1073741824, 0) +" TB"+'</b> ';
                        if (d >= 1048576) return this.series.name  +': <b>' + Highcharts.numberFormat(d / 1048576, 0) +" GB"+'</b> ';
                        if (d >= 1024) return  this.series.name  +': <b>' + Highcharts.numberFormat(d / 1024, 0) +" MB"+'</b> ';
                        return this.series.name  +': <b>' + Highcharts.numberFormat(d, 0) +" KB"+'</b> ';
                    }},
                    series: this.storefileSize.series,
                });

                this.compacting.chart = new Highcharts.Chart('compactingChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Num. Compacting Cells' },
                    colors: this.colors,
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    tooltip: {formatter: function () {
                            return  this.series.name + '<br/>' +'<b> Count: ' + Highcharts.numberFormat(Math.abs(this.point.y), 0)+"</b>";}},
                    series: this.compacting.series,
                });

                this.compacted.chart = new Highcharts.Chart('compactedChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Num. Compacted Cells' },
                    colors: this.colors,
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    tooltip: {formatter: function () {
                        return  this.series.name + '<br/>' +'<b> Count: ' + Highcharts.numberFormat(Math.abs(this.point.y), 0)+"</b>";}},
                    series: this.compacted.series,
                });

                this.updateCharts();
            },

            updateCharts() {
                let ts = (new Date(this.ds.timestamp)).getTime()
                let ds = this.ds.ds;

                let redraw = false;
                let shift = this.shift;

                let ss = [];

                let heaps = [[], []]; //free, used

                /** Requests Per Second **/
                for (let i = 0; i < ds.length; i++) {
                    ss.push(ds[i].ServerName)
                    this.request.chart.series[i].addPoint([ts, ds[i].baseStatsTable.Requests_Per_Second], redraw, shift, true);

                    this.heapUsed.chart.series[i].addPoint([ts, ds[i].memoryStatsTable.Used_Heap / 1024], redraw, shift, true);

                    this.requestRead.chart.series[i].addPoint([ts, ds[i].requestStatsTable.Read_Request_Count], redraw, shift, true);
                    this.requestFiltered.chart.series[i].addPoint([ts, ds[i].requestStatsTable.Filtered_Read_Request_Count], redraw, shift, true);
                    this.requestWrite.chart.series[i].addPoint([ts, ds[i].requestStatsTable.Write_Request_Count], redraw,shift, true);

                    this.storefileSize.chart.series[i].addPoint([ts, ds[i].storeStatsTable.Storefile_Size], redraw,shift, true);

                    this.compacting.chart.series[i].addPoint([ts, ds[i].compactionStatsTable.Num_Compacting_Cells], redraw,shift, true);
                    this.compacted.chart.series[i].addPoint([ts, ds[i].compactionStatsTable.Num_Compacted_Cells], redraw,shift, true);


                    tuh = Number(ds[i].memoryStatsTable.Used_Heap / ds[i].memoryStatsTable.Max_Heap).toFixed(2);
                    heaps[0].push(1 - tuh);
                    heaps[1].push(Number(tuh));

                }
                //this.request.chart.redraw();
                /** Requests Per Second **/

                this.heap.chart.series[0].setData(heaps[0])
                this.heap.chart.series[1].setData(heaps[1])

                this.ss = ss;
               
                this.heap.chart.xAxis[0].setCategories(this.ss);

                if(this.model == 1){
                    this.drawAll()
                }
                else if (this.model == 2 && this.id % 10 == 0) {
                    this.drawAll()
                }
              
            },

            drawAll(){
                this.request.chart.redraw();
                this.heapUsed.chart.redraw();
                this.requestRead.chart.redraw();
                this.requestFiltered.chart.redraw();
                this.requestWrite.chart.redraw();
                this.storefileSize.chart.redraw();
                this.compacting.chart.redraw();
                this.compacted.chart.redraw();
                this.heap.chart.redraw();
            },

            getFirstData() {
                axios.get("/api/getNextData", {params: { 'id': this.id } }).then(
                    (res) => {
                        let ds = res.data.data.ds;
                        this.id = ds.id;
                        this.ds = ds;
                        this.initCharts();
                    })
                    .catch(function (error) { console.log(error); });
            },
            getNextData() {
                if(this.model == 2 && this.id > this.idRange[1]){
                    this.drawAll();
                    clearInterval(this.job);
                    return;
                }
                axios.get("/api/getNextData", {params: { 'id': this.id } }).then(
                    (res) => {
                        let ds = res.data.data.ds;
                        if (!(ds.id > this.id)) { return; } //如果不是新数据，则跳过

                        this.id = ds.id;
                        this.ds = ds;
                        //console.log(ds)
                        this.updateCharts();
                        if (++this.xNum >= this.maxNum) this.shift = true;
                    })
                    .catch(function (error) { console.log(error); });
            },

            getQueryString(name) {
                var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
                var reg_rewrite = new RegExp("(^|/)" + name + "/([^/]*)(/|$)", "i");
                var r = window.location.search.substr(1).match(reg);
                var q = window.location.pathname.substr(1).match(reg_rewrite);
                if (r != null) {  return unescape(r[2]);} 
                else if (q != null) { return unescape(q[2]);} 
                else { return null; }
            },

        },
        filters: {
            formatStorageUnit(d) {
                if (d == undefined) { return '0 KB' }
                if (d >= 1073741824) return (d / 1073741824).toFixed(2) + " TB"
                if (d >= 1048576) return (d / 1048576).toFixed(2) + " GB"
                if (d >= 1024) return (d / 1024) + " MB"
                return d + " KB"
            },

            formatNum(n) {
                if (n == undefined) { return '0' }
                n = n + ""
                let re = /\d{1,3}(?=(\d{3})+$)/g;
                let n1 = n.replace(/^(\d+)((\.\d+)?)$/, function (s, s1, s2) { return s1.replace(re, "$&,") + s2; });
                return n1;
            },

            fix2(d) {
                if (d == undefined) { return '' }
                return Number(d).toFixed(2);
            }
        }
    })

</script>
{% endblock %}